package remato.client.controller;

import java.lang.reflect.UndeclaredThrowableException;
import java.net.URL;
import java.util.Iterator;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.IProgressService;

import remato.client.controller.exceptions.RematoClientException;
import remato.client.model.NodeChild;
import remato.client.model.NodeParent;
import remato.client.model.WrapperFactory;
import remato.client.model.facade.IModelPersistable;
import remato.client.model.facade.INodeChild;
import remato.client.model.facade.ModelSystem;
import remato.client.view.util.ReflectionHelper;
import remato.client.view.util.ReflectionRunnableWithProgress;
import remato.domain.common.RequirementSystem;

import com.wgo.bpot.common.transport.exception.RematoException;
import com.wgo.precise.client.common.session.PreciseSession;

/**
 * This class holds information concerning a user session. It is instansiated 
 * once per login and is disposed at logout.
 * 
 * @author Petter L. H. Eide <petter@eide.biz>
 * @version $Id: ClientSession.java,v 1.3 2006-02-06 09:29:08 petterei Exp $
 */
public class ClientSession {
    
    private WrapperFactory wrapperFactory;
    private PreciseSession session = null;
    
    public ClientSession(PreciseSession session) {
    	this.session = session;
    	wrapperFactory = new WrapperFactory(session.<RequirementSystem>getRootSystem());
//    	wrapperFactory = new WrapperFactory(session.getRootSystem(RequirementSystem.class));
    }

    public void dispose(){
    	wrapperFactory = null;
        session = null;
    }
    
	public WrapperFactory getWrapperFactory() {
		return wrapperFactory;
	}

	public boolean isDirty() { 
		if (getDomainSession() != null) {
			return getDomainSession().isAnyDirty();
		}
		return false;
	}

	public IModelPersistable getModelItem(Long identifier) {
        IModelPersistable wrapper = null;
        Iterator<ModelSystem<?>> systemIterator = wrapperFactory.getSystems().iterator();
        while (systemIterator.hasNext() && null == wrapper) {
        	Iterator<? extends INodeChild> childrenIterator = systemIterator.next().getChildren().iterator();
            while (childrenIterator.hasNext() && null == wrapper) {
        		wrapper = getModelItem(childrenIterator.next(), identifier);
        	}
        }
        return wrapper;
	}
	
    @SuppressWarnings("unchecked")
	private INodeChild getModelItem( INodeChild child, Long identifier ) {
        INodeChild childMatch = null;
        if (child.getIdentifier().equals(identifier)) {
            childMatch = child;
        } else if (child instanceof NodeParent) {
            for ( Object parentChild : ((NodeParent)child).getChildren() ) {
                childMatch = getModelItem((NodeChild)parentChild, identifier);
                if (childMatch != null) {
                    return childMatch;
                }
            }
        }
        return childMatch;
    }

	public PreciseSession getDomainSession() {
		return session;
	}

	public synchronized void saveAll() {
        IRunnableWithProgress op = new ReflectionRunnableWithProgress("Saving all changes.", ReflectionHelper.retrieveMethod(getClass().getSimpleName(), session.getClass(), "save"),session);
		Throwable exception = null;
		IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
		try {
			progressService.busyCursorWhile(op);
		} catch (RematoException e) {
			exception = e;
		} catch (UndeclaredThrowableException e){
			exception = e.getUndeclaredThrowable();
		} catch (Throwable e) {
			exception = e;
		}
		RequirementPlugin.getInstance().getEditorWindowManager().flushNonPersistedItemsEditors();
		if (null != exception) {
			RequirementPlugin.log(new RematoClientException(new ModelStatus(IStatus.ERROR, "Error when saving.", exception)));
		}
		RequirementPlugin.getInstance().notifyModelUpdated(null);//TODO
	}
	
	public URL getServerContextUrl() {
		return session.getServerContextUrl();
	}
	
}
